package com.edt.ichannel.api.service.component;


import cc.edt.iceutils2.string.IceStringUtils;
import cc.edt.iceutils3.json.IceFastJsonUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Component
public class RedisLock {

    private static final Logger logger = LogManager.getLogger(RedisLock.class);

//    /**
//     *  单个业务持有锁的时间30s,防止死锁
//     */
//    private final static long LOCK_EXPIRE = 30 * 1000L;

    /**
     * 默认30ms尝试一次
     */
    private final static long LOCK_TRY_INTERVAL = 30L;

    /**
     *  默认尝试30s
     */
    private final static long LOCK_TRY_TIMEOUT = 30 * 1000L;

    @Resource(name = "redisTemplate")
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 操作redis获取全局锁
     *
     * @param lockKey          锁的名称
     * @param lockValue     锁的值
     * @param timeout        获取的超时时间
     * @param tryInterval    多少ms尝试一次
     * @return true 获取成功，false获取失败
     */
    private boolean  getLock(String lockKey, Object lockValue, long timeout, long tryInterval){

        try{
            if(IceStringUtils.isAnyBlank(lockKey)){
                return false;
            }
            long startTime = System.currentTimeMillis();
            while (true){
                if(redisTemplate.opsForValue().setIfAbsent(lockKey,lockValue)){
                    redisTemplate.opsForValue().set(lockKey,lockValue,timeout, TimeUnit.MILLISECONDS);
                    logger.info(Thread.currentThread().getName() + " : get lock");
                    return true;
                }else {
                    logger.info(Thread.currentThread().getName() + " : ----> locking is exist!!!");
                }
                if(System.currentTimeMillis() - startTime > timeout*100){
                    logger.info(Thread.currentThread().getName() + " : ----> locking is timeout!!!");
                    return false;
                }
                Thread.sleep(tryInterval);
            }
        }catch (Exception e){
            e.printStackTrace();
            logger.error(e.getMessage());
            return false;
        }
    }


    /**
     * 尝试获取全局锁 值跟键同一个值
     *
     * @param lockKey 锁的名称
     * @return true 获取成功，false获取失败
     */
    public boolean tryLock(String lockKey) {
        return getLock(lockKey,lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL);
    }

    /**
     * 尝试获取全局锁
     *
     * @param lockKey 锁的名称
     * @param lockValue     锁的值
     * @return true 获取成功，false获取失败
     */
    public boolean tryLock(String lockKey, String lockValue) {
        return getLock(lockKey,lockValue, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL);
    }
    /**
     * 尝试获取全局锁
     *
     * @param lockKey 锁的名称
     * @param lockValue     锁的值
     * @return true 获取成功，false获取失败
     */
    public boolean tryLock(String lockKey, Object lockValue) {
        String value = IceFastJsonUtils.toJsonString(lockKey);
        return getLock(lockKey,lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL);
    }

    /**
     * 尝试获取全局锁
     *
     * @param lockKey    锁的名称
     * @param lockValue     锁的值
     * @param timeout 获取超时时间 单位ms
     * @return true 获取成功，false获取失败
     */
    public boolean tryLock(String lockKey, String lockValue , long timeout) {
        return getLock(lockKey,lockValue, timeout, LOCK_TRY_INTERVAL);
    }


    /**
     * 尝试获取全局锁
     *
     * @param lockKey        锁的名称
     *  @param lockValue     锁的值
     * @param timeout     获取锁的超时时间
     * @param tryInterval 多少毫秒尝试获取一次
     * @return true 获取成功，false获取失败
     */
    public boolean tryLock(String lockKey, String lockValue, long timeout, long tryInterval) {
        return getLock(lockKey,lockValue, timeout, tryInterval);
    }



    /**
     * 释放锁
     */
    public void releaseLock(String lockKey) {
        if (IceStringUtils.isNotBlank(lockKey)) {
            logger.info(Thread.currentThread().getName() + " : del lock");
            redisTemplate.delete(lockKey);
        }
    }

    /**
     * 释放锁
     * 判断，值相等才释放
     */
    public void releaseLock(String lockKey, String lockValue) {
        //防止解锁其他线程
        if (IceStringUtils.isNoneBlank(lockKey,lockValue)) {
            if(redisTemplate.opsForValue().setIfAbsent(lockKey,lockValue)){
                //设置成功，则说明当前锁已经不存在，删除
                redisTemplate.delete(lockKey);
            }else {
                //不成功 判断值，相等说明是值相等的所，释放
                String value = (String) redisTemplate.opsForValue().get(lockKey);
                logger.info("lockvalue :"+lockKey +" redisValue:"+value+" compare result: "+IceStringUtils.equals(lockValue, value));
                if(IceStringUtils.equals(lockValue, value)){
                    redisTemplate.delete(lockKey);
                }
            }
        }
    }
}
